package edu.wright.ceg4980.year2013.keyboard;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.LinkedList;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JEditorPane;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPasswordField;

@SuppressWarnings("serial")
public class CollectionScreen extends JPanel {
	private int numTries;
	
	private String pswd;
	
	private boolean isPswdValid;
	
	private JEditorPane infoEditorPane;
	
	private JPasswordField pswdField;
	
	private JButton resetButton;
	
	private LinkedList<KeyData> keyPresses;
	
	private LinkedList<KeyData> keyReleases;
	
	public CollectionScreen() {
		super(new BorderLayout());
		setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
		
		numTries = 0;
		pswd = "";
		keyPresses = new LinkedList<KeyData>();
		keyReleases = new LinkedList<KeyData>();
		
		infoEditorPane = new JEditorPane("text/html", "");
		infoEditorPane.setEditable(false);
		infoEditorPane.setBackground(getBackground());
		updateInfoTA();
		
		pswdField = new JPasswordField(15);
		pswdField.addKeyListener(new PasswordKeyListener());
		
		resetButton = new JButton("Reset");
		resetButton.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				CollectionScreen.this.reset();
			}
		});
		
		JPanel northPanel = new JPanel(new BorderLayout(0, 5));
		
		JPanel pswdPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
		
		add(northPanel, BorderLayout.NORTH);
			northPanel.add(infoEditorPane, BorderLayout.CENTER);
			northPanel.add(pswdPanel, BorderLayout.SOUTH);
				pswdPanel.add(pswdField);
				pswdPanel.add(resetButton);

		reset();
	}
	
	public void setTries(int numTries) {
		this.numTries = numTries;
		updateInfoTA();
	}
	
	public void setCorrectPassword(String password) {
		this.pswd = password;
		updateInfoTA();
	}
	
	public char[] getEnteredPassword() {
		return pswdField.getPassword();
	}
	
	private void updateInfoTA() {
		final String infoString = String.format(
				"Next, we need to record some data about your typing patterns. " +
				"Enter your password correctly <strong>%d</strong> more times.\n\n" +
				"Note that pressing Backspace, Delete, or any other non-password related key will invalidate your password. " +
				"If the password field turns red, your password is invalid; you then need to press the 'Reset' button to start typing again. " +
				"Click the 'Next' button to submit a password.<br/><br/>" +
				"As a reminder, your password is <strong>%s</strong>.",
				numTries,
				pswd);
		CollectionScreen.this.infoEditorPane.setText(infoString);
	}
	
	// returns null if the password is invalid
	public KeySequenceData getTypingData() {
		String pswd = new String(pswdField.getPassword());
		if (isPswdValid) {
			if (pswd.equals(this.pswd)) {
				return new KeySequenceData(keyPresses, keyReleases);
			} else {
				JOptionPane.showMessageDialog(this, "The password you typed is incorrect. Try Again", "Incorrect Password", JOptionPane.ERROR_MESSAGE);
				reset();
			}
		} else {
			JOptionPane.showMessageDialog(this, "You pressed an invalid key while typing your password. Try Again", "Invalid Key Pressed", JOptionPane.ERROR_MESSAGE);
			reset();
		}
		return null;
	}
	
	public void clearTypingData() {
		keyPresses.clear();
		keyReleases.clear();
	}
	
	public void clearPassword() {
		pswdField.setText("");
	}
	
	public void reset() {
		clearTypingData();
		setPasswordValid(true);
		clearPassword();
	}
	
	private void setPasswordValid(boolean isPasswordValid) {
		isPswdValid = isPasswordValid;
		if (isPasswordValid) {
			pswdField.setBorder(BorderFactory.createLineBorder(Color.BLACK));
		} else {
			pswdField.setBorder(BorderFactory.createLineBorder(Color.RED));
		}
	}
	
	private static boolean isKeyValid(int keyCode) {
		switch (keyCode) {
		case KeyEvent.VK_SHIFT:
		case KeyEvent.VK_BACK_QUOTE:
		case KeyEvent.VK_1:
		case KeyEvent.VK_2:
		case KeyEvent.VK_3:
		case KeyEvent.VK_4:
		case KeyEvent.VK_5:
		case KeyEvent.VK_6:
		case KeyEvent.VK_7:
		case KeyEvent.VK_8:
		case KeyEvent.VK_9:
		case KeyEvent.VK_0:
		case KeyEvent.VK_MINUS:
		case KeyEvent.VK_EQUALS:
		case KeyEvent.VK_A:
		case KeyEvent.VK_B:
		case KeyEvent.VK_C:
		case KeyEvent.VK_D:
		case KeyEvent.VK_E:
		case KeyEvent.VK_F:
		case KeyEvent.VK_G:
		case KeyEvent.VK_H:
		case KeyEvent.VK_I:
		case KeyEvent.VK_J:
		case KeyEvent.VK_K:
		case KeyEvent.VK_L:
		case KeyEvent.VK_M:
		case KeyEvent.VK_N:
		case KeyEvent.VK_O:
		case KeyEvent.VK_P:
		case KeyEvent.VK_Q:
		case KeyEvent.VK_R:
		case KeyEvent.VK_S:
		case KeyEvent.VK_T:
		case KeyEvent.VK_U:
		case KeyEvent.VK_V:
		case KeyEvent.VK_W:
		case KeyEvent.VK_X:
		case KeyEvent.VK_Y:
		case KeyEvent.VK_Z:
		case KeyEvent.VK_OPEN_BRACKET:
		case KeyEvent.VK_CLOSE_BRACKET:
		case KeyEvent.VK_BACK_SLASH:
		case KeyEvent.VK_BRACERIGHT:
		case KeyEvent.VK_SEMICOLON:
		case KeyEvent.VK_QUOTE:
		case KeyEvent.VK_COMMA:
		case KeyEvent.VK_PERIOD:
		case KeyEvent.VK_SLASH:
		case KeyEvent.VK_SPACE:
		case KeyEvent.VK_NUMPAD0:
		case KeyEvent.VK_NUMPAD1:
		case KeyEvent.VK_NUMPAD2:
		case KeyEvent.VK_NUMPAD3:
		case KeyEvent.VK_NUMPAD4:
		case KeyEvent.VK_NUMPAD5:
		case KeyEvent.VK_NUMPAD6:
		case KeyEvent.VK_NUMPAD7:
		case KeyEvent.VK_NUMPAD8:
		case KeyEvent.VK_NUMPAD9:
		case KeyEvent.VK_ADD:
		case KeyEvent.VK_SUBTRACT:
		case KeyEvent.VK_MULTIPLY:
		case KeyEvent.VK_DIVIDE:
		case KeyEvent.VK_DECIMAL:
			return true;
		default:
			return false;
		}
	}
	
	private class PasswordKeyListener extends KeyAdapter {
		@Override
		public void keyPressed(KeyEvent e) {
			if (CollectionScreen.this.isPswdValid) {
				int keyCode = e.getKeyCode();
				if (CollectionScreen.isKeyValid(keyCode)) {
					CollectionScreen.this.keyPresses.add(new KeyData(keyCode, e.getWhen()));
				} else {
					CollectionScreen.this.setPasswordValid(false);
				}
			}
		}
		
		@Override
		public void keyReleased(KeyEvent e) {
			if (CollectionScreen.this.isPswdValid) {
				int keyCode = e.getKeyCode();
				if (CollectionScreen.isKeyValid(keyCode)) {
					CollectionScreen.this.keyReleases.add(new KeyData(keyCode, e.getWhen()));
				} else {
					CollectionScreen.this.setPasswordValid(false);
				}
			}
		}
	}
}
